package com.onpositive.knowledge.model.value.audits;

import com.onpositive.data.IPropertyConstants;
import com.onpositive.knowledge.model.values.DescribedValue;
import com.onpositive.knowledge.model.values.IHasValue;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.semantic.model.api.property.ValueUtils;

public abstract class AbstractValueAudit extends AuditSourceContainer implements IValueAudit {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	
	

	

	public AbstractValueAudit() {		
	}

	

	@Override
	public void perform(IProperty prop, Iterable<Object> objects, AbstractAuditResult pm )
	{
		Boolean isService = prop.getMeta().getSingleValue( IPropertyConstants.CHAR_IS_SERVICE_PROPERTY, Boolean.class, null) ;
		if( isService != null && isService )
			return ;
		
		Boolean isDepricated = prop.getMeta().getSingleValue( IPropertyConstants.CHAR_DEPRICATED_LABEL, Boolean.class, null);
		if( isDepricated != null && isDepricated )
			return ;
		
		if(pm != null)
			pm.propertyId=prop.getId();		
	
		for (Object o : objects)
			gatherStat(o, prop,pm);

		if(pm != null)
			pm.looksApplyable = onStatsCompleted(pm);

		for (Object o : objects)
			processStat(o, prop,pm);
	}
// previously we had this function:	
//	protected AbstractAuditResult createResult() ; {
//		return new GeneralAuditResult();
//	}

	protected abstract boolean onStatsCompleted(AbstractAuditResult pm);

	private void processStat(Object o, IProperty prop, AbstractAuditResult pm)
	{
		Boolean isService = Boolean.parseBoolean( prop.getMeta().getSingleValue( IPropertyConstants.CHAR_IS_SERVICE_PROPERTY, String.class, null) );
		if( isService != null && isService )
			return ;
		
		Boolean isDepricated = Boolean.parseBoolean( prop.getMeta().getSingleValue( IPropertyConstants.CHAR_DEPRICATED_LABEL, String.class, null) );
		if( isDepricated != null && isDepricated )
			return ;
		
		Object value = prop.getValue(o);
		if ( value == null )
			return ;
		
		Iterable<Object> collection = ValueUtils.toCollection(value);

		for (Object s : collection) {
			if (!(s instanceof DescribedValue)) {
				s = new DescribedValue( s, null);
			}
			if (isSuspicious(o, (DescribedValue) s, prop,pm)) {
				pm.addAsSuspicious(o);
			}
		}
	}

	protected void gatherStat(Object o, IProperty prop, AbstractAuditResult pm)
	{
		Object value = prop.getValue(o);
		if ( value == null )
			return ;
		
		Iterable<Object> collection = ValueUtils.toCollection(value);

		processCollection(o, prop, pm, collection);
	}



	private void processCollection(Object o, IProperty prop,
			AbstractAuditResult pm, Iterable<Object> collection) {
		for (Object s : collection) {
			
			while( s instanceof IHasValue )
				s = ((IHasValue)s).value() ;			
			
			if( s instanceof Iterable<?> )
				processCollection(o, prop, pm, (Iterable<Object>) s ) ;
			else
			{				
				if (!(s instanceof DescribedValue)) {
					s = new DescribedValue(s, null);
				}				
				preprocessValue(o, (DescribedValue) s, prop,pm );
			}
		}
	}

	protected abstract void preprocessValue(Object o, DescribedValue value,
			IProperty prop, AbstractAuditResult pm);

	protected abstract boolean isSuspicious(Object o, DescribedValue value,
			IProperty prop,AbstractAuditResult pm);

}
